import AVKit
import Flutter
import Foundation
import SnapKit
import UIKit

public class SystemWindowsPlugin: NSObject, FlutterPlugin, AVPictureInPictureControllerDelegate {
    private var registrar: FlutterPluginRegistrar
    private var playerLayer: AVPlayerLayer?
    private var player: AVPlayer?
    private var pipController: AVPictureInPictureController?
    private var textBox: TextBoxWindows?
    private var recordBox: RecordBoxWindows?

    var rootView: UIViewController?

    private var stackView: UIStackView?

    public static func register(with registrar: FlutterPluginRegistrar) {
        let channel = FlutterMethodChannel(name: "system.windows", binaryMessenger: registrar.messenger())
        let instance = SystemWindowsPlugin(registrar)
        registrar.addApplicationDelegate(instance)
        registrar.addMethodCallDelegate(instance, channel: channel)
    }

    init(_ registrar: FlutterPluginRegistrar) {
        self.registrar = registrar
        super.init()
    }

    public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
        let value = textBox?.handle(call, result) ?? recordBox?.handle(call, result)
        if value == true {
            return
        }
        switch call.method {
        case "show":
            rootView = UIApplication.shared.keyWindow?.rootViewController
            result(showPictureInPicture(call.arguments as! [String: Any?]))
        case "isActive":
            result(pipController?.isPictureInPictureActive ?? false)
        case "toggle":
            let value = call.arguments as! Bool
            if value {
                /// 切换前台
            } else {
                /// 切换后台
                let targetSelect = #selector(NSXPCConnection.suspend)
                if UIApplication.shared.responds(to: targetSelect) {
                    UIApplication.shared.perform(targetSelect)
                }
            }
            result(nil)
        case "isSupported":
            result(isSupported())
        case "dispose":
            dispose()
            result(pipController == nil)
        default:
            result(nil)
        }
    }

    func showPictureInPicture(_ args: [String: Any?]) -> Bool {
        do {
            try AVAudioSession.sharedInstance().setCategory(.playAndRecord, options: .mixWithOthers)
            try AVAudioSession.sharedInstance().setActive(true, options: [])
        } catch {
            return false
        }
        dispose()
        let type = args["type"] as! Int
        if type == 0 {
            textBox = TextBoxWindows(args)
            stackView = textBox!.stackView
        } else if type == 1 {
            recordBox = RecordBoxWindows(args)
            stackView = recordBox!.stackView
        }
        if stackView == nil {
            return false
        }
        let asset = args["path"] as! String
        let packageName = args["packageName"] as? String
        let assetPath: String
        if packageName != nil {
            assetPath = registrar.lookupKey(forAsset: asset, fromPackage: packageName!)
        } else {
            assetPath = registrar.lookupKey(forAsset: asset)
        }
        let bundlePath = Bundle.main.path(forResource: assetPath, ofType: nil)
        if bundlePath == nil {
            return false
        }
        if isSupported() {
            playerLayer = AVPlayerLayer()
            playerLayer!.frame = .init(x: args["left"] as! Double, y: args["top"] as! Double, width: args["width"] as! Double, height: args["height"] as! Double)
            player = AVPlayer(playerItem: AVPlayerItem(asset: AVURLAsset(url: URL(fileURLWithPath: bundlePath!))))
            playerLayer!.player = player
            player!.isMuted = true
            player!.allowsExternalPlayback = true
            player!.accessibilityElementsHidden = true
            pipController = AVPictureInPictureController(playerLayer: playerLayer!)
            pipController!.delegate = self
            pipController!.setValue(1, forKey: "requiresLinearPlayback")
            pipController!.setValue(1, forKey: "controlsStyle")
            if #available(iOS 14.2, *) {
                pipController!.canStartPictureInPictureAutomaticallyFromInline = true
            } else {}
            player!.play()
            rootView?.view.layer.addSublayer(playerLayer!)
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.4) {
                self.pipController!.startPictureInPicture()
            }
            return true
        } else {
            print("当前设备不支持PiP")
        }

        UIApplication.shared.beginBackgroundTask {
            UIApplication.shared.endBackgroundTask(UIBackgroundTaskIdentifier.invalid)
        }
        return false
    }

    public func dispose() {
        recordBox?.close()
        recordBox = nil
        textBox?.close()
        textBox = nil
        stackView?.removeFromSuperview()
        stackView = nil
        pipController?.stopPictureInPicture()
        pipController = nil
        playerLayer?.removeFromSuperlayer()
        playerLayer = nil
        player?.replaceCurrentItem(with: nil)
        player = nil
    }

    public func isSupported() -> Bool {
        AVPictureInPictureController.isPictureInPictureSupported()
    }

    public func applicationWillEnterForeground(_ application: UIApplication) {
        // print("进入前台")
    }

    public func applicationDidEnterBackground(_ application: UIApplication) {
        //  print("进入后台")
    }

    public func applicationDidBecomeActive(_ application: UIApplication) {}

    public func pictureInPictureControllerDidStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
        if let window = UIApplication.shared.windows.first {
            if stackView != nil, rootView != nil {
                rootView?.view.addSubview(stackView!)
                window.addSubview(stackView!)
                stackView!.snp.makeConstraints { make -> Void in
                    make.edges.equalToSuperview()
                }
            }
        }
    }

    public func pictureInPictureControllerDidStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
        dispose()
    }
}
